import java.io.File;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.lightstreamer.interfaces.metadata.CreditsException;
import com.lightstreamer.interfaces.metadata.MetadataProviderException;
import com.lightstreamer.interfaces.metadata.NotificationException;


public class ChatMetadataAdapter extends LiteralBasedProvider {

    /**
     * The associated feed to which messages will be forwarded;
     * it is the Data Adapter itself.
     */
    private volatile ChatDataAdapter chatFeed;

    /**
     * Unique identification of the Adapter Set. It is used to uniquely
     * identify the related Data Adapter instance;
     * see feedMap on ChatDataAdapter.
     */
    private String adapterSetId;

    /**
     * Private logger; a specific "LS_demos_Logger.Chat" category
     * should be supplied by log4j configuration.
     */
    private Logger logger;

    /**
     * Used as a Set, to keep unique identifiers for the currently connected
     * clients.
     * Each client is uniquely identified by the client IP address and the
     * HTTP user agent; in case of conflicts, a custom progressive is appended
     * to the user agent. This set lists the concatenations of the current
     * IP and user agent pairs, to help determining uniqueness.
     */
    private ConcurrentHashMap<String,Object> uaIpPairs = new ConcurrentHashMap<String,Object>();

    public ChatMetadataAdapter() {
    }

    public void init(Map params, File configDir) throws MetadataProviderException {
        //Call super's init method to handle basic Metadata Adapter features
        super.init(params,configDir);

        logger = Logger.getLogger("LS_demos_Logger.Chat");

        // Read the Adapter Set name, which is supplied by the Server as a parameter
        this.adapterSetId = (String) params.get("adapters_conf.id");
    }

    /**
     * Triggered by a client "sendMessage" call.
     * The message encodes a chat message from the client.
     */
    public void notifyUserMessage(String user, String session, String message)
        throws NotificationException, CreditsException {

        if (message == null) {
            logger.log(Level.WARNING, "Null message received");
            throw new NotificationException("Null message received");
        }

        //Split the string on the | character
        //The message must be of the form "CHAT|message"
        String[] pieces = message.split("\\|");

        if (pieces[0].equals("CHAT")) {
	        this.loadChatFeed();
	        this.handleChatMessage(pieces,message,session);
        }

        if (pieces[0].equals("GAME_PLAY")) {
        	this.loadChatFeed();
	        this.handlePlayMessage(pieces,message,session);
        }

        if (pieces[0].equals("PLAYER_PROFILE_UPDATES")) {
        	this.loadChatFeed();
	        this.handlePlayerProfileUpdateMessage(pieces,message,session);
        }

        if (pieces[0].equals("ADD_FRIEND")) {
        	this.loadChatFeed();
	        this.handleAddFriendMessage(pieces,message,session);
        }

        if (pieces[0].equals("ACCEPT_FRIEND")) {
        	this.loadChatFeed();
	        this.handleAcceptFriendMessage(pieces,message,session);
        }
    }

	public void notifyNewSession(String user, String session, Map sessionInfo)
            throws CreditsException, NotificationException {
    }

    public void notifySessionClose(String session) throws NotificationException {
    }

    private void loadChatFeed() throws CreditsException {
        if (this.chatFeed == null) {
             try {
                 // Get the ChatDataAdapter instance to bind it with this
                 // Metadata Adapter and send chat messages through it
                 this.chatFeed = ChatDataAdapter.feedMap.get(this.adapterSetId);
             } catch(Throwable t) {
                 // It can happen if the Chat Data Adapter jar was not even
                 // included in the Adapter Set lib directory (the Chat
                 // Data Adapter could not be included in the Adapter Set as well)
                 logger.log(Level.SEVERE, "ChatDataAdapter class was not loaded: " + t);
                 throw new CreditsException(0, "No chat feed available", "No chat feed available");
             }

             if (this.chatFeed == null) {
                 // The feed is not yet available on the static map, maybe the
                 // Chat Data Adapter was not included in the Adapter Set
            	 logger.log(Level.SEVERE, "ChatDataAdapter not found");
                 throw new CreditsException(0, "No chat feed available", "No chat feed available");
             }
        }
    }

    private void handleChatMessage(String[] pieces, String message, String session) throws NotificationException {
    	String gameId = pieces[1];
    	String msg = pieces[2];
    	String player = pieces[3];
    	String time = pieces[4];
    	String playerId = pieces[5];
        this.chatFeed.sendMessage(player, gameId, msg, time, playerId);
    }

    private void handlePlayMessage(String[] pieces, String message, String session) throws NotificationException {
    	String gameId = pieces[1];
    	String playerId = pieces[2];
    	String playerName = pieces[3];
    	String playType = pieces[4];
    	Map<String, String> metadata = new HashMap<String, String>();

    	if (pieces.length >= 5) {
	    	for (int i = 5; i < pieces.length; i++) {
	    		String[] data = pieces[i].split(":");
	    		metadata.put(data[0], data[1]);
	    	}
    	}

        this.chatFeed.sendPlay(gameId, playerId, playerName, playType, metadata);
    }

    private void handlePlayerProfileUpdateMessage(String[] pieces, String message, String session) {
    	String playerId = pieces[1];
    	String field = pieces[2];
    	String oldValue = pieces[3];
    	String newValue = pieces[4];
    	String gameIds = pieces[5];
    	this.chatFeed.sendPlayerProfileUpdateMessage(playerId, field, oldValue, newValue, gameIds);

	}

    private void handleAddFriendMessage(String[] pieces, String message, String session) {
    	String playerName = pieces[1];
    	String friendId = pieces[2];
    	String playerId = pieces[3];
    	String playId = pieces[4];
    	this.chatFeed.sendAddFriendMessage(playerName, friendId, playerId, playId);
	}

    private void handleAcceptFriendMessage(String[] pieces, String message, String session) {
    	String playerName = pieces[1];
    	String friendId = pieces[2];
    	String playerId = pieces[3];
    	this.chatFeed.sendAcceptFriendMessage(playerName, friendId, playerId);
	}
}